package com.demo.topics;

import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.demo.topics.util.SessionManager;
import com.google.android.youtube.player.YouTubeBaseActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayerView;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.services.youtube.YouTube;
import com.google.api.services.youtube.model.*;

import java.io.IOException;

/**
 * This Activity renders a view that shows an view with a built in YouTube player, with options to add to a playlist
 * if the user is logged in.
 *
 * @author Ikai Lan <ikai@google.com>
 */
public class VideoPlayerActivity extends YouTubeBaseActivity implements YouTubePlayer.OnInitializedListener {
    private static final String TAG = VideoPlayerActivity.class.getSimpleName();

    public static final String VIDEO_ID = "video_id";
    public static final String PLAYLIST_ID = "playlist_id";
    public static final String VIDEO_TITLE = "video_title";
    public static final String VIDEO_DESCRIPTION = "video_description";
    public static final String PLAYLIST_TITLE = "playlist_title";
    public static final String TOPIC_NAME = "topic_name";
    private static final String PUBLIC = "public";
    private static final String YOUTUBE_VIDEO = "youtube#video";

    // Views
    private YouTubePlayer mPlayer;
    private TextView mVideoTitleView;
    private TextView mVideoDescriptionView;
    private Button mAddToPlaylist;

    // Player state
    private String mVideoId;
    private String mPlaylistId;
    private String mVideoTitle;
    private String mVideoDescription;
    private String mPlaylistTitle;
    private String mTopicName;

    private SessionManager mSessionManager;

    public void onCreate(Bundle savedInstanceState) {
        // If this line is not included, this class will throw a NullPointerException complaining that the
        // "listener cannot be null"
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_video_player);

        mSessionManager = SessionManager.getInstance(this);

        // Initialize the data from the Intent
        Bundle bundle = getIntent().getExtras();
        mVideoId = bundle.getString(VIDEO_ID, null);
        mPlaylistId = bundle.getString(PLAYLIST_ID, null);
        mVideoTitle = bundle.getString(VIDEO_TITLE);
        mVideoDescription = bundle.getString(VIDEO_DESCRIPTION, "");
        mPlaylistTitle = bundle.getString(PLAYLIST_TITLE, null);
        mTopicName = bundle.getString(TOPIC_NAME, null);


        // Initialize the various views
        mVideoTitleView = (TextView) findViewById(R.id.video_title);
        mVideoDescriptionView = (TextView) findViewById(R.id.video_description);
        mAddToPlaylist = (Button) findViewById(R.id.add_to_playlist);

        // If we are viewing a video search result and logged in, present playlist options
        if (mTopicName != null && mSessionManager.isUserLoggedIn()) {

            // Initialize the add to playlist button
            mAddToPlaylist.setVisibility(View.VISIBLE);
            mAddToPlaylist.setText(getResources().getString(R.string.add_to_playlist) + " \"" + mTopicName + "\"");

            // Bind a listener to add to playlist
            mAddToPlaylist.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    new AddToPlaylistTask().execute();
                }
            });
        }

        // Initialize the YouTube player view
        final String apiKey = getResources().getString(R.string.api_key);
        YouTubePlayerView playerView = (YouTubePlayerView) findViewById(R.id.youtube_view);
        playerView.initialize(apiKey, this);

        // Add data to views
        mVideoTitleView.setText(mVideoTitle);
        mVideoDescriptionView.setText(mVideoDescription);
    }


    @Override
    public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean b) {
        mPlayer = youTubePlayer;

        // Cue either a video player or a playlist player, depending on what we received from the Intent bundle
        if (mVideoId != null) {
            mPlayer.cueVideo(mVideoId);
            setTitle(getResources().getString(R.string.video) + ": " + mVideoTitle);
        } else if (mPlaylistId != null) {
            Log.d(TAG, "Playing playlist: " + mPlaylistId);
            mPlayer.cuePlaylist(mPlaylistId);
            setTitle(getResources().getString(R.string.playlist) + ": " + mPlaylistTitle);
        } else {
            // We should probably crash, since this state should never be reached
        }
    }

    @Override
    public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult youTubeInitializationResult) {
        // TODO implement failure conditions
    }


    /**
     * Handler class for adding an item to a playlist. We're just going to use instance variables for this
     * item instead of creating a "holder" object for the state.
     */
    private class AddToPlaylistTask extends AsyncTask<Void, String, PlaylistItem> {

        @Override
        protected PlaylistItem doInBackground(Void... params) {
            String generatedPlaylistName = getResources().getString(R.string.topic) + ": " + mTopicName;

            String authToken = mSessionManager.getAuthToken();
            GoogleCredential credential = new GoogleCredential();
            credential.setAccessToken(authToken);

            HttpTransport httpTransport = new NetHttpTransport();
            JsonFactory jsonFactory = new JacksonFactory();

            YouTube yt = new YouTube.Builder(httpTransport, jsonFactory,
                    credential).setApplicationName("YouTubeMobileCodeLab/0.1")
                    .build();
            try {

                publishProgress("Checking to see if playlist exists ...");

                // Check to see if the playlist exists
                PlaylistListResponse playlistResponse = yt.playlists().list("id,snippet")
                        .setMaxResults(50l)
                        .setMine(true)
                        .setFields("items(id,snippet/title)")
                        .execute();

                Playlist playlist = null;
                for (Playlist playlistItem : playlistResponse.getItems()) {
                    if (playlistItem.getSnippet().getTitle().equals(generatedPlaylistName)) {
                        publishProgress("Playlist exists already");
                        playlist = playlistItem;
                    }
                }

                // If it does not, create it. This is a three step process:
                // - Create the snippet
                // - Create the privacy status
                // - Attach these to a new Playlist instance
                // - Call insert with the playlist instance
                if (playlist == null) {
                    publishProgress("Playlist does not exist. Creating ... ");

                    // Create the playlist snippet
                    PlaylistSnippet playlistSnippet = new PlaylistSnippet();
                    playlistSnippet.setTitle(generatedPlaylistName);
                    playlistSnippet.setDescription(getResources().getString(R.string.autogenerated_playlist_about)
                            + ": " + mTopicName);

                    // Here we set the privacy status to private since we don't want to share these
                    PlaylistStatus playlistStatus = new PlaylistStatus();
                    playlistStatus.setPrivacyStatus(PUBLIC);

                    // Instantiate a new playlist and give it the two attributes
                    playlist = new Playlist();
                    playlist.setSnippet(playlistSnippet);
                    playlist.setStatus(playlistStatus);

                    // make the API call
                    playlist = yt.playlists()
                            .insert("snippet,status", playlist)
                            .execute();
                }

                // Update the playlist to add the item.
                // Let's create a resource ID containing the video ID
                ResourceId resourceId = new ResourceId();
                resourceId.setKind(YOUTUBE_VIDEO);
                resourceId.setVideoId(mVideoId);

                // We'll need to create a PlaylistItem instance
                PlaylistItemSnippet playlistItemSnippet = new PlaylistItemSnippet();
                playlistItemSnippet.setTitle(mVideoTitle);
                playlistItemSnippet.setPlaylistId(playlist.getId());
                playlistItemSnippet.setResourceId(resourceId);

                // Now create the playlist item
                PlaylistItem playlistItem = new PlaylistItem();
                playlistItem.setSnippet(playlistItemSnippet);

                publishProgress("Adding video to playlist ...");
                // TODO rename this variable
                PlaylistItem itemInsertResponse =  yt.playlistItems()
                        .insert("snippet,contentDetails", playlistItem)
                        .execute();
                Log.d(TAG, "Added item to playlist. Response: " + itemInsertResponse.toString());
                return itemInsertResponse;
            } catch (IOException e) {
                Log.e(TAG, "Got IO exception: " + e);
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(String... values) {
            for(String update : values) {
                Log.d(TAG, update);
                // TODO update the UI depending on where we are
            }
        }

        @Override
        protected void onPostExecute(PlaylistItem playlistItem) {
            // TODO update the UI and note that the item has been added
            // TODO refresh the items in PlaylistFragment
        }
    }
}